/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <ipc_skeleton.h>
#include <iremote_broker.h>
#include <message_option.h>
#include <message_parcel.h>
#include <peer_holder.h>
#include <securec.h>
#include <sys/unistd.h>

#include "accesstoken_kit.h"
#include "nativetoken_kit.h"

namespace OHOS {
BrokerRegistration &BrokerRegistration::Get()
{
    static BrokerRegistration instance;
    return instance;
}

BrokerRegistration::~BrokerRegistration()
{
    isUnloading = true;
    std::lock_guard<std::mutex> lockGuard(creatorMutex_);
    for (auto it = creators_.begin(); it != creators_.end();) {
        it = creators_.erase(it);
    }
    for (auto it1 = objects_.begin(); it1 != objects_.end();) {
        BrokerDelegatorBase *object = reinterpret_cast<BrokerDelegatorBase *>(*it1);
        object->isSoUnloaded = true;
        it1 = objects_.erase(it1);
    }
}

bool BrokerRegistration::Register(const std::u16string &descriptor, const Constructor &creator,
    const BrokerDelegatorBase *object)
{
    if (descriptor.empty()) {
        return false;
    }

    std::lock_guard<std::mutex> lockGuard(creatorMutex_);
    auto it = creators_.find(descriptor);
    bool ret = false;
    if (it == creators_.end()) {
        ret = creators_.insert({ descriptor, creator }).second;
    }
    auto it1 = std::find_if(objects_.begin(), objects_.end(), [descriptor](uintptr_t id) {
        const BrokerDelegatorBase *object = reinterpret_cast<BrokerDelegatorBase *>(id);
        return object->descriptor_ == descriptor;
    });
    if (it1 == objects_.end()) {
        objects_.push_back(reinterpret_cast<uintptr_t>(object));
    }
    return ret;
}

void BrokerRegistration::Unregister(const std::u16string &descriptor)
{
    if (isUnloading) {
//        ZLOGE(LABEL, "BrokerRegistration is Unloading");
        return;
    }
    std::lock_guard<std::mutex> lockGuard(creatorMutex_);
    if (!descriptor.empty()) {
        auto it = creators_.find(descriptor);
        if (it != creators_.end()) {
            creators_.erase(it);
        }
        auto it1 = std::find_if(objects_.begin(), objects_.end(), [descriptor](uintptr_t id) {
            const BrokerDelegatorBase *object = reinterpret_cast<BrokerDelegatorBase *>(id);
            return object->descriptor_ == descriptor;
        });
        if (it1 != objects_.end()) {
            objects_.erase(it1);
        }
    }
}

sptr<IRemoteBroker> BrokerRegistration::NewInstance(const std::u16string &descriptor, const sptr<IRemoteObject> &object)
{
    std::lock_guard<std::mutex> lockGuard(creatorMutex_);

    sptr<IRemoteBroker> broker;
    if (object != nullptr) {
        auto it = creators_.find(descriptor);
        if (it != creators_.end()) {
            broker = it->second(object);
        }
//        if (object->IsProxyObject()) {
//
//        } else {
//            broker = object->AsInterface().GetRefPtr();
//        }
    }
    return broker;
}

PeerHolder::PeerHolder(const sptr<IRemoteObject> &object)
    : remoteObject_(object) {};
sptr<IRemoteObject> PeerHolder::Remote() { return remoteObject_; }
pid_t IPCSkeleton::GetCallingUid() { return 1000; } //getuid(); }
pid_t IPCSkeleton::GetCallingPid() { return getpid(); }
uint32_t IPCSkeleton::GetCallingTokenID()
{
    NativeTokenInfoParams params{0};
    params.processName = "distributed_test";
    params.aplStr = "distributed_test";
    return GetAccessTokenId(&params);
}
uint64_t IPCSkeleton::GetSelfTokenID()
{
    return 0;
}
MessageOption::MessageOption(int flags, int waitTime) {}
void MessageOption::SetFlags(int flags) {}
int MessageOption::GetFlags() const { return 0; }
void MessageOption::SetWaitTime(int waitTime) {}
int MessageOption::GetWaitTime() const { return 0; }
MessageParcel::MessageParcel() : rawDataSize_(0) {}
MessageParcel::~MessageParcel() {}
MessageParcel::MessageParcel(Allocator *allocator)
    : Parcel(allocator) {}
bool MessageParcel::WriteRemoteObject(const sptr<IRemoteObject> &object)
{
    remoteObjects_.push(object);
    return true;
}
sptr<IRemoteObject> MessageParcel::ReadRemoteObject()
{
    if (remoteObjects_.empty()) {
        return nullptr;
    }
    auto object = remoteObjects_.front();
    remoteObjects_.pop();
    return object;
}
bool MessageParcel::WriteFileDescriptor(int fd) { return false; }
int MessageParcel::ReadFileDescriptor() { return 0; }
bool MessageParcel::ContainFileDescriptors() const { return false; }
bool MessageParcel::WriteInterfaceToken(std::u16string name)
{
    token_ = name;
    return true;
}
std::u16string MessageParcel::ReadInterfaceToken()
{
    return token_;
}
bool MessageParcel::WriteRawData(const void *data, size_t size)
{
    std::shared_ptr<char> rawData(new char[rawDataSize_ + size]);
    memcpy_s(&(rawData.get())[rawDataSize_], size, data, size);
    if (rawData_ != nullptr) {
        memcpy_s(rawData.get(), rawDataSize_, rawData_.get(), rawDataSize_);
    }
    rawData_ = rawData;
    rawDataSize_ += size;
    return true;
}
const void *MessageParcel::ReadRawData(size_t size)
{
    if (rawDataSize_ < size) {
        return nullptr;
    }
    rawDataSize_ -= size;
    return &(rawData_.get()[rawDataSize_]);
}

bool MessageParcel::RestoreRawData(std::shared_ptr<char> rawData, size_t size)
{
    rawData_ = rawData;
    rawDataSize_ = size;
    return true;
}
const void *MessageParcel::GetRawData() const { return rawData_.get(); }
size_t MessageParcel::GetRawDataSize() const { return rawDataSize_; }
size_t MessageParcel::GetRawDataCapacity() const { return MAX_RAWDATA_SIZE; }
void MessageParcel::WriteNoException() {}
int32_t MessageParcel::ReadException() { return 0; }
bool MessageParcel::WriteAshmem(sptr<Ashmem> ashmem) { return false; }
sptr<Ashmem> MessageParcel::ReadAshmem() { return sptr<Ashmem>(); }
void MessageParcel::ClearFileDescriptor() {}
bool MessageParcel::Append(MessageParcel &data) { return false; }
bool MessageParcel::WriteDBinderProxy(const sptr<IRemoteObject> &object, uint32_t handle, uint64_t stubIndex) { return false;}
}